"""
带认证的TTS API客户端
支持访问需要认证的音频文件端点
"""
import requests
import json
import os
import base64
from typing import Optional, Dict, Any, List
import time


class AuthenticatedTTSClient:
    """带认证的TTS API客户端"""
    
    def __init__(self, base_url: str = "http://localhost:8021"):
        """初始化客户端"""
        self.base_url = base_url
        self.api_prefix = "/api/v1"
        self.token = None
        self.token_expiry = 0
        
        # 默认的访客级别凭据
        self.username = "guest"
        self.password = "guest"
    
    def login(self, username: str = "testuser", password: str = "testpassword") -> bool:
        """登录API获取认证令牌"""
        self.username = username
        self.password = password
        
        url = f"{self.base_url}{self.api_prefix}/auth/token"
        
        # 使用表单数据格式发送登录请求
        data = {
            "username": username,
            "password": password,
            "grant_type": "password"
        }
        
        try:
            response = requests.post(
                url, 
                data=data,  # 使用表单数据而非JSON
                headers={"Content-Type": "application/x-www-form-urlencoded"}
            )
            response.raise_for_status()
            
            # 解析令牌
            result = response.json()
            self.token = result.get("access_token")
            
            # 设置令牌过期时间 (默认1小时后)
            self.token_expiry = time.time() + 3600
            
            print(f"登录成功，令牌: {self.token[:10]}...")
            return True
        except Exception as e:
            print(f"登录失败: {e}")
            # 尝试替代方法：直接创建一个基础认证头
            auth_string = base64.b64encode(f"{username}:{password}".encode()).decode()
            self.token = f"Basic {auth_string}"
            print(f"使用基础认证替代方法")
            return False
    
    def get_headers(self) -> Dict[str, str]:
        """获取包含认证信息的请求头"""
        headers = {
            "Content-Type": "application/json"
        }
        
        # 检查令牌是否存在且未过期
        if self.token:
            if self.token.startswith("Basic "):
                headers["Authorization"] = self.token
            else:
                headers["Authorization"] = f"Bearer {self.token}"
        
        return headers
    
    def ensure_authenticated(self) -> bool:
        """确保客户端已认证"""
        if not self.token or (self.token_expiry > 0 and time.time() > self.token_expiry):
            return self.login(self.username, self.password)
        return True
    
    def synthesize_text(self, text: str, voice_id: Optional[str] = None, 
                        format: str = "wav") -> Dict[str, Any]:
        """合成语音"""
        # 确保已认证
        self.ensure_authenticated()
        
        url = f"{self.base_url}{self.api_prefix}/tts/synthesize"
        
        payload = {
            "text": text,
            "format": format
        }
        
        if voice_id:
            payload["voice_id"] = voice_id
        
        try:
            response = requests.post(url, json=payload, headers=self.get_headers())
            response.raise_for_status()
            
            # 解析响应
            result = response.json()
            
            # 正确访问字段
            if result.get("success"):
                print(f"合成成功: {result.get('message')}")
                print(f"音频URL: {result.get('audio_url')}")
                print(f"音频时长: {result.get('duration')} 秒")
                print(f"音频格式: {result.get('format')}")
                
                # 返回结果
                return result
            else:
                print(f"合成失败: {result.get('message')}")
                return result
                
        except requests.exceptions.HTTPError as e:
            print(f"HTTP错误: {e}")
            try:
                error_data = response.json()
                print(f"API错误: {error_data}")
            except:
                print(f"响应内容: {response.text}")
        except Exception as e:
            print(f"其他错误: {e}")
        
        return {"success": False, "message": "请求失败"}
    
    def download_audio(self, audio_url: str, output_path: str) -> bool:
        """下载音频文件"""
        # 确保已认证
        self.ensure_authenticated()
        
        # 构建完整URL
        if not audio_url.startswith("http"):
            if audio_url.startswith('/api/v1/audio/'):
                # 尝试多种可能的URL路径
                urls_to_try = [
                    # 原始路径
                    f"{self.base_url}{audio_url}",
                    # 修正路径 - 将 /api/v1/audio/ 改为 /api/v1/tts/audio/
                    f"{self.base_url}{audio_url.replace('/api/v1/audio/', '/api/v1/tts/audio/')}",
                    # 直接访问文件系统路径（如果API支持）
                    f"{self.base_url}/data/cache/audio/{os.path.basename(audio_url)}"
                ]
            else:
                urls_to_try = [f"{self.base_url}{audio_url}"]
        else:
            urls_to_try = [audio_url]
        
        # 尝试每个可能的URL
        success = False
        for url in urls_to_try:
            try:
                print(f"尝试下载: {url}")
                response = requests.get(url, headers=self.get_headers())
                response.raise_for_status()
                
                # 检查是否是音频内容
                content_type = response.headers.get('Content-Type', '')
                print(f"响应内容类型: {content_type}")
                
                if content_type.startswith('audio/') or content_type == 'application/octet-stream':
                    # 保存文件
                    with open(output_path, 'wb') as f:
                        f.write(response.content)
                    
                    print(f"音频已保存到: {output_path}")
                    success = True
                    break
                else:
                    print(f"警告: 响应不是音频内容 ({content_type})")
                    
            except requests.exceptions.HTTPError as e:
                print(f"尝试URL {url} 失败: HTTP错误 {e.response.status_code}")
        
        if not success:
            # 尝试直接从音频缓存目录获取文件
            try:
                filename = os.path.basename(audio_url)
                # 直接从文件系统读取音频文件
                direct_path = f"./data/cache/audio/{filename}"
                
                if os.path.exists(direct_path):
                    print(f"尝试从本地缓存直接读取文件: {direct_path}")
                    with open(direct_path, 'rb') as src:
                        with open(output_path, 'wb') as dst:
                            dst.write(src.read())
                    print(f"从本地缓存成功读取并保存到: {output_path}")
                    return True
            except Exception as e:
                print(f"尝试直接读取文件失败: {e}")
        
        return success
    
    def get_available_voices(self) -> List[Dict[str, Any]]:
        """获取可用语音列表"""
        # 确保已认证
        self.ensure_authenticated()
        
        url = f"{self.base_url}{self.api_prefix}/tts/voices"
        
        try:
            response = requests.get(url, headers=self.get_headers())
            response.raise_for_status()
            
            result = response.json()
            if "voices" in result:
                return result["voices"]
            return []
        except Exception as e:
            print(f"获取语音列表失败: {e}")
            return []


# 如果直接运行此脚本
if __name__ == "__main__":
    # 创建TTS客户端实例
    client = AuthenticatedTTSClient(base_url="http://localhost:8021")
    
    # 登录API
    client.login()
    
    # 合成语音示例
    text = "欢迎使用离线语言播放系统，这是一个测试语音合成的示例。"
    result = client.synthesize_text(text, format="wav")
    
    # 如果合成成功，下载音频
    if result.get("success") and result.get("audio_url"):
        # 创建output目录
        os.makedirs("output", exist_ok=True)
        
        # 下载音频
        client.download_audio(
            result["audio_url"],
            f"output/tts_example.{result.get('format', 'wav')}"
        )
    
    # 获取可用语音示例
    print("\n获取可用语音列表:")
    voices = client.get_available_voices()
    for voice in voices:
        print(f"ID: {voice.get('id')}, 名称: {voice.get('name')}, 语言: {voice.get('language')}")